package core.reports;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import common.util.DateUtils;

import core.Container;
import core.Item;
import core.ItemManager;
import core.Product;
import core.ProductGroup;
import core.ProductManager;
import core.RootStorageUnit;
import core.StorageUnit;

/**
 * This implementation of IReportVisitor generates the Expired Items Report.
 * @author Royce
 *
 */
public class ExpiredItemsVisitor implements IReportVisitor {
	IReportBuilder _builder;
	TraversingType _type;
	
	/**
	 * Default no-arg constructor
	 * @throws IOException 
	 */
	public ExpiredItemsVisitor(IReportBuilder builder) throws IOException {
		setBuilder(builder);
		_type = TraversingType.PREORDER;
	}
	
	/**
	 * Sets the report Builder that this visitor will use.
	 * @param builder any implementation of IReportBuilder.
	 * @throws IOException 
	 */
	private void setBuilder(IReportBuilder builder) throws IOException {
		_builder = builder;
		builder.startTable("", 6);
		builder.addCell("Description");
		builder.addCell("Storage Unit");
		builder.addCell("Product Group");
		builder.addCell("Entry Date");
		builder.addCell("Expire Date");
		builder.addCell("Item Barcode");

	}

	/**
	 * Called when the Root Storage Unit is visited.
	 * @param rsu the RootStorageUnit.
	 */
	@Override
	public void visitRoot(RootStorageUnit rsu) {
		//Not interested in the root, as items must be in a SU or PG.

	}

	/**
	 * Called when a Storage Unit is visited
	 * @param su a reference to the visited StorageUnit
	 */
	@Override
	public void visitStorageUnit(StorageUnit su) {	
		visitContainer(su);
	}
	
	/**
	 * Called when a Product Group is visited
	 * @param pg a reference to the visited ProductGroup
	 */
	@Override
	public void visitProductGroup(ProductGroup pg) {		
		visitContainer(pg);		
	}
	
	private void visitContainer(Container c) {
		Iterator<Item> itemIter = c.getItems();
		if(itemIter == null) return;
		List<Item> items = new ArrayList<Item>();
		while(itemIter.hasNext()) {
			Item curItem = itemIter.next();
			if (curItem.getExpirationDate().before(Calendar.getInstance()) &&
					!(curItem.getEntryDate().equals(curItem.getExpirationDate()))) {
				//only keep the items we want to add
				items.add(curItem);
			}
		}
		
		if(items.size() > 0) printItems(items);
	}

	private void printItems(List<Item> items) {
		Collections.sort(items, new Comparator<Item>() {
			@Override
			public int compare(Item arg0, Item arg1) {
				int cmp1 = arg0.getDescription().compareTo(arg1.getDescription());
				if (cmp1 != 0) {
					return cmp1;
				}
				
				int cmp2 = arg0.getEntryDate().compareTo(arg1.getEntryDate());
				if (cmp2 != 0) {
					return cmp2;
				}
				
				return 0;
			}	
		});
		
		for (Item item : items) {
			printOneItem(item);
		}
	}

	private void printOneItem(Item item) {
		if (item.isUsed())
			return;
		try {
			_builder.addCell(item.getDescription());
			if (item.getContainer() instanceof StorageUnit) {
				_builder.addCell(item.getContainer());
				_builder.addCell("");
			}
			else if (item.getContainer() instanceof ProductGroup) {
				_builder.addCell(getSUParent(item));
				_builder.addCell(item.getContainer());
			}
			else {
				_builder.addCell("");
				_builder.addCell("");
			}
			_builder.addCell(printDate(item.getEntryDate()));
			_builder.addCell(printDate(item.getExpirationDate()));
			_builder.addCell(item.getBarcodeString());
		}
		catch (IOException e) {
			//ignore this item for now.
		}
	}
	
	private StorageUnit getSUParent(Item i) {
		Container c = i.getContainer();
		while(!(c instanceof StorageUnit)) {
			c = c.getParent();
		}
		return (StorageUnit)c;
	}
	
	private String printDate(Calendar date) {
		return DateUtils.formatDate(date.getTime());
	}

	/**
	 * Called when a Product is visited
	 * @param product a reference to the visited Product
	 */
	@Override
	public void visitProduct(Product product) {
		//Should I use this?

	}

	/**
	 * Called when an Item is visited
	 * @param item a reference to the visited Item
	 */
	@Override
	public void visitItem(Item item) {
		//Should I use this?

	}

	@Override
	public TraversingType getType() {
		return _type;
	}

	@Override
	public void visitProductManager(ProductManager pm) {
		//not used by ExpiredItemsVisitor
		
	}

	@Override
	public void visitItemManager(ItemManager im) {
		//not used by ExpiredItemsVisitor
		
	}

	@Override
	public void onDone() {
		// TODO Auto-generated method stub
		
	}
}
